﻿using Basic.RPC.Abstract;
using BeetleX.XRPC.Clients;
using BeetleX.XRPC.Packets;
using System.Collections.Concurrent;

namespace Basic.RPC.Impl;

/// <summary>
/// XRpc客户端
/// </summary>
internal class BeetleXRpcClient : IRpcClient
{
    private bool IsInitialize;
    private List<RpcClientService> RpcInterfaces;

    private ConcurrentDictionary<Guid, InternalXRpcClient> TypeDict;
    private ConcurrentDictionary<string, InternalXRpcClient> ClientDict;
    private IDictionary<string, IDictionary<string, string>> ServiceDict;

    public BeetleXRpcClient(List<RpcClientService> rpcInterfaces, IDictionary<string, IDictionary<string, string>> serviceDict)
    {
        RpcInterfaces = rpcInterfaces;
        ServiceDict = serviceDict;
    }

    public void Initialize()
    {
        if (IsInitialize == true)
            return;

        TypeDict = new ConcurrentDictionary<Guid, InternalXRpcClient>();
        ClientDict = new ConcurrentDictionary<string, InternalXRpcClient>();

        foreach (var rpcInfo in RpcInterfaces)
        {
            string rpcServiceName = rpcInfo.ServiceName;
            var rpcList = ServiceDict.Values.Where(s => s.TryGetValue("Name", out string serviceName) && string.Equals(serviceName, rpcServiceName)).ToArray();

            if (rpcList.Length > 0)
            {
                InternalXRpcClient internalClient = new InternalXRpcClient(rpcList);
                internalClient.Initialize();
                ClientDict.TryAdd(rpcServiceName, internalClient);

                var types = rpcInfo.InterfaceTypes;
                foreach (var type in types)
                    TypeDict.TryAdd(type.GUID, internalClient);
            }
        }

    }

    public T GetService<T>() where T : class
    {
        if (TypeDict.TryGetValue(typeof(T).GUID, out var client))
        {
            return client.GetClients().Create<T>();
        }

        return null;
    }

    /// <summary>
    /// 内部RPC
    /// </summary>
    internal class InternalXRpcClient
    {
        private int Index = 0;
        private List<XRPCClient> Clients;
        private IDictionary<string, string>[] MetaArray;

        public InternalXRpcClient(IDictionary<string, string>[] rpcArray)
        {
            MetaArray = rpcArray;
        }

        public void Initialize()
        {
            int len = MetaArray.Length;
            Clients = new List<XRPCClient>(len);
            for (int i = 0; i < len; i++)
            {
                var meta = MetaArray[i];
                if (meta.TryGetValue("RpcPort", out string rpcPort) == true && !string.IsNullOrWhiteSpace(rpcPort))
                {
                    XRPCClient client = new XRPCClient(meta["IP"], int.Parse(rpcPort));
                    client.Options.ParameterFormater = new JsonPacket();
                    Clients.Add(client);
                }
            }
        }


        public XRPCClient GetClients()
        {
            Index++;
            if (Index >= Clients.Count)
                Index = 0;

            return Clients[Index];
        }

    }
}